package com.lagou.edu.factory;

import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.service.TransferService;
import com.lagou.edu.trans.Autowired;
import com.lagou.edu.trans.Service;
import com.lagou.edu.trans.Transactional;
import com.lagou.edu.utils.ClassUtil;
import org.apache.commons.lang.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class BeanFactory_Annotation {
    //包路径
    private static String packagePath;
    private static List<Class<?>> classes;
    //存放注解对象的容器
    private static ConcurrentHashMap<String,Object> beans;

    public static void initBeanIoc(String packPath){
        packagePath =packPath;
        classes = ClassUtil.getClasses(packagePath);
        beans =new ConcurrentHashMap<String,Object>();
        try {
            initBeans();
            initResource();
            initTransation();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private static void initResource() throws Exception {
        //遍历所有的注解对象
        Set<Map.Entry<String, Object>> entrySet = beans.entrySet();
        for (Map.Entry<String, Object> entry:entrySet){
            //获取注解对象，判断是否有属性的依赖注入
            Object value = entry.getValue();
            attriAssign(value);
        }
    }

    private static void initBeans() throws Exception {
        //使用java反射机制获取包下的所有类
        //List<Class<?>> classes = ClassUtil.getClasses(packagePath);
        ConcurrentHashMap<String, Object> beanss = findClassExistAnnotation(classes);
        if(beanss == null || beanss.isEmpty()){
            throw new Exception("该包下没有注解的类");
        }
    }

    private static ConcurrentHashMap<String,Object> findClassExistAnnotation(List<Class<?>> classes) throws IllegalAccessException, InstantiationException {
        for (Class<?> clazz:classes){
            Service annotation =clazz.getDeclaredAnnotation(Service.class);
            if(annotation !=null){
                //获取当前类名
//                String className = clazz.getSimpleName();
                //当前类名小写
//                String beanId = toLowerCaseFirstOne(className);
                String beanId  =annotation.value();
                Object bean = clazz.newInstance();
                beans.put(beanId,bean);
            }

        }
        return beans;
    }

    private static void initTransation(){
        for (Class<?> clazz:classes){
            Transactional transactional =clazz.getDeclaredAnnotation(Transactional.class);
            if(transactional !=null){
                Service service_annotation =clazz.getDeclaredAnnotation(Service.class);
                //获取原对象
                String beanId  =service_annotation.value();
                Object oBean = beans.get(beanId);//被代理对象
                //转为代理对象
                ProxyFactory proxyFactory = (ProxyFactory) beans.get("proxyFactory");
                Object proxy = proxyFactory.getJdkProxy(oBean);//代理对象
                //代理对象替换原对象
                beans.put(beanId,proxy);
            }

        }
    }

    public static Object getBean(String beanId) {
//        if (StringUtils.isEmpty(beanId)){
//            throw new Exception("bean的ID不存在");
//        }
        //从bean对象池map中获取
        Object bean = beans.get(beanId);
        return bean;
    }

    //首字母转小写
    public static String toLowerCaseFirstOne(String s){
        if(Character.isLowerCase(s.charAt(0))){
            return s;
        }else{
            return (new StringBuffer()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

    private static void attriAssign(Object obj) throws Exception {
        //使用反射机制获取当前类的所有属性
        Class<? extends Object> class1 = obj.getClass();
        Field[] fields =  class1.getDeclaredFields();
        for (Field field:fields){
            Autowired autowired = field.getDeclaredAnnotation(Autowired.class);
            if(autowired !=null){
                //获取属性名称
//                String name = field.getName();
                String name =autowired.value();
                Object bean =getBean(name);
                field.setAccessible(true);
                //给属性赋值
                field.set(obj,bean);
            }
        }
    }
}
